<!--DevicePropertiesDialog.vue-->
<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { message } from "@/utils/message";
import { FormInstance } from "element-plus";
import {
  addDevice,
  Channel,
  Device,
  DeviceChannel,
  DeviceProperties,
  DeviceProperty,
  DeviceTypeCategory,
  findChannel,
  updateDevice
} from "@/api/deviceApi";
import DevicePropertyInput from "@/views/devices/components/DevicePropertyInput.vue";
import {
  extractContentBeforeBrackets,
  extractContentInBrackets
} from "@/views/devices/components/DevicePropertiesUtil";

const props = defineProps({
  visible: { type: Boolean, default: false },
  data: { type: Object as () => Device, default: () => ({}) },
  deviceTypeCategories: { type: Array<DeviceTypeCategory>, default: () => [] },
  deviceProperties: {
    type: Object as () => DeviceProperties,
    default: () => ({})
  }
});

const svg = `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `;

const ruleFormRef = ref<FormInstance>();
const formVisible = ref(false);
const deviceChannelsMap = ref<Record<string, Array<DeviceChannel>>>({});
const deviceChannelChannels = ref<Record<string, Array<Channel>>>({});
const deviceChannelChangeCount = ref(0);
const isUpdateDialog = ref(false);
const loading = ref(false);

const fetchDeviceChannels = async (model, spec, displayName) => {
  console.log(model);
  if (model === "THERMOCOUPLE" && spec === "") {
    return [];
  }
  let response = await findChannel(model, spec);
  if (!response.data || response.data.length == 0) {
    response = await findChannel(model, "TypeJ");
    // message(`找不到可用的${displayName}`, { type: "warning" });
  }
  return response.data || [];
};

function fetchDeviceChannelChannels(propertyName) {
  if (!formData.value[propertyName]) return;
  const selectedDeviceChannel = deviceChannelsMap.value[propertyName].find(
    dc => dc.id === formData.value[propertyName]
  );
  if (!selectedDeviceChannel) return;
  deviceChannelChannels.value[propertyName] = selectedDeviceChannel.channels;
}

function setDefaultValue(data: any, property: DeviceProperty) {
  const {
    dataType,
    property: propertyName,
    defaultValue,
    min,
    enumValues
  } = property;
  if (dataType.startsWith("findChannel")) {
    return;
  }
  if (defaultValue !== undefined) {
    data[propertyName] =
      dataType === "enum"
        ? formatEnumValue(enumValues, defaultValue)
        : defaultValue;
  } else {
    const defaults = {
      string: "",
      number: min || 0,
      enum: enumValues && enumValues.length > 0 ? enumValues[0] : "",
      boolean: false
    };
    data[propertyName] = defaults[dataType];
  }
}

function enrichDefaultData(model: string, defaultData: any) {
  props.deviceProperties[model].forEach((property: DeviceProperty) => {
    setDefaultValue(defaultData, property);
  });
}

const getDefaultFormData = (): Record<string, any> => {
  const defaultData: any = { ...props.data };
  // console.log("defaultData", JSON.stringify(defaultData));
  if (defaultData.id) {
    // 有ID为更新
    return defaultData;
  }
  const model = props.data.model;
  if (model && props.deviceProperties[model]) {
    enrichDefaultData(model, defaultData);
  }
  if (props.deviceProperties["DEFAULT"]) {
    enrichDefaultData("DEFAULT", defaultData);
  }
  return defaultData;
};

const formData = ref<Record<string, any>>(getDefaultFormData());

const generateRules = (properties: Array<DeviceProperty>) => {
  return properties.reduce((rules, { required, property, displayName }) => {
    rules[property] = [
      {
        required,
        message: `请输入${displayName}`,
        trigger: "blur"
      }
    ];
    return rules;
  }, {});
};

const rules = computed(() => {
  return formData.value.model
    ? {
        ...generateRules(props.deviceProperties["DEFAULT"]),
        ...generateRules(props.deviceProperties[formData.value.model])
      }
    : {};
});

const submitForm = async () => {
  if (!ruleFormRef.value) return;
  await ruleFormRef.value.validate(async valid => {
    if (valid) {
      //console.log("add-device", JSON.stringify(formData.value));
      loading.value = true;
      let response;
      if (formData.value.id) {
        formData.value.deviceId = formData.value.id;
        response = await updateDevice(formData.value);
      } else {
        response = await addDevice(formData.value);
      }
      if (response.errorCode === 0) {
        message("提交成功", { type: "success" });
        formVisible.value = false;
        ruleFormRef.value.resetFields();

        // 发出 device-added 事件
        loading.value = false;
        emit("device-added");
      } else {
        message(response.message, { type: "error" });
        loading.value = false;
      }
    }
  });
};

const closeDialog = () => {
  formVisible.value = false;
  ruleFormRef.value?.resetFields();
};

const setDeviceChannelMap = async () => {
  for (const property: DeviceProperty of props.deviceProperties[
    formData.value.model
  ]) {
    if (property.dataType.startsWith("findChannel")) {
      const properties = property.property.split("&");
      const devicePropertyName = properties[0];
      const channelPropertyName = properties[1];
      const params = extractContentInBrackets(property.dataType);
      let model, spec;
      if (params.includes(",")) {
        model = params.split(",")[0].trim();
        spec = formData.value.spec || "";
      } else {
        model = params;
        spec = "";
      }
      deviceChannelsMap.value[devicePropertyName] = await fetchDeviceChannels(
        model,
        spec,
        property.displayName
      );
      console.log(deviceChannelsMap);
      console.log(deviceChannelChangeCount.value);
      // 如果是更新设备，第一次不要清空选项
      if (deviceChannelChangeCount.value > 0 || !isUpdateDialog.value) {
        formData.value[devicePropertyName] = null;
        formData.value[channelPropertyName] = null;
      }
      deviceChannelChangeCount.value++;
      // watch([() => formData.value[devicePropertyName]], () => {
      //   formData.value[channelPropertyName] = null;
      // });
      // 重置选择框
    }
  }
};

const emit = defineEmits(["update:visible", "device-added"]);

watch(formVisible, val => emit("update:visible", val));
watch(props, ({ visible }) => {
  deviceChannelChangeCount.value = 0;
  isUpdateDialog.value = props.data.id > 0;
  formVisible.value = visible;
  formData.value = getDefaultFormData();
});
watch(
  [() => formData.value.model, () => formData.value.spec],
  setDeviceChannelMap
);

function formatEnumValue(enumValues: Array<any>, val: unknown): unknown {
  if (!enumValues) {
    return val;
  }
  enumValues.forEach(value => {
    if (typeof value !== "string") {
      return val;
    }
    if (extractContentBeforeBrackets(value) === val) {
      return value;
    }
  });
  return val;
}
</script>

<template>
  <el-dialog
    v-model="formVisible"
    :before-close="closeDialog"
    :width="680"
    :title="formData.id ? '管理设备' : '添加设备'"
  >
    <el-form
      ref="ruleFormRef"
      :model="formData"
      :rules="rules"
      label-width="100px"
    >
      <el-form-item label="设备类型" prop="model">
        <el-cascader
          v-model="formData.model"
          :options="deviceTypeCategories"
          :props="{ expandTrigger: 'hover' }"
          disabled
          placeholder="请选择设备类型"
          style="width: 100%"
        />
      </el-form-item>
      <div
        v-for="property in [
          ...deviceProperties['DEFAULT'],
          ...deviceProperties[formData.model]
        ]"
        :key="property.property"
      >
        <DevicePropertyInput
          v-model="formData[property.property]"
          :property="property"
        />
        <el-form-item
          :label="property.displayName"
          v-if="property.dataType.startsWith('findChannel')"
        >
          <el-select
            v-model="formData[property.property.split('&')[0]]"
            :placeholder="`请选择${property.displayName}`"
            @change="
              () => fetchDeviceChannelChannels(property.property.split('&')[0])
            "
          >
            <el-option
              v-for="deviceChannel in deviceChannelsMap[
                property.property.split('&')[0]
              ]"
              :key="deviceChannel.id"
              :label="deviceChannel.name"
              :value="deviceChannel.id"
            />
          </el-select>
          <span style="width: 12px" />
          <el-select
            v-model="formData[property.property.split('&')[1]]"
            placeholder="请选择通道"
          >
            <el-option
              v-for="channel in deviceChannelChannels[
                property.property.split('&')[0]
              ]"
              :key="channel.channelIdx"
              :label="'通道' + channel.channelIdx"
              :value="channel.channelIdx"
            />
          </el-select>
        </el-form-item>
      </div>
    </el-form>
    <template #footer>
      <el-button @click="closeDialog">取消</el-button>

      <el-button
        :disabled="loading"
        v-loading="loading"
        :element-loading-svg="svg"
        element-loading-svg-view-box="-10, -10, 50, 50"
        type="primary"
        @click="submitForm"
      >
        确定</el-button
      >
    </template>
  </el-dialog>
</template>
